package models

import (
	"errors"
	"fmt"
	"github.com/astaxie/beego/orm"
	"reflect"
	"strings"
	"time"
)

type Author struct {
	Id          int       `orm:"column(id);pk;auto"`
	Name        string    `orm:"column(name)"`
	Email       string    `orm:"column(email);null"`
	Profile     string    `orm:"column(profile);null"`
	CreatedTime time.Time `orm:"column(created_time);auto_now_add;type(timestamp with time zone)"`
}

func init() {
	orm.RegisterModel(new(Author))
}

func CreateAuthor(author *Author) (int64, error) {
	log.Debug("Function CreateAuthor input param:{author:%v}", author)
	o := orm.NewOrm()
	id, err := o.Insert(author)
	log.Debug("Function CreateAuthor return:{error:%v,id:%v}", err, id)
	return id, err
}

func GetAuthors(query map[string]string, fields []string, sortby []string, order []string, offset int64, limit int64) ([]interface{}, int64, error) {

	log.Debug("Function GetAuthors input param:{query:%v,fields:%v,sortby:%v,order:%v,offset:%v,limit:%v}", query, fields, sortby, order, offset, limit)

	o := orm.NewOrm()
	qs := o.QueryTable(new(Author))

	//query
	if len(query) > 0 {
		for k, v := range query {
			key := strings.Replace(k, ".", "__", -1)
			qs = qs.Filter(key, v)
		}
	}

	//order by
	var orderBys []string
	if len(sortby) > 0 {
		if len(sortby) == len(order) {
			for k, v := range sortby {
				if strings.ToUpper(order[k]) == "ASC" {
					orderBys = append(orderBys, v)
				} else if strings.ToUpper(order[k]) == "DESC" {
					orderBys = append(orderBys, fmt.Sprintf("-%v", v))
				} else {
					return nil, 0, errors.New("Error: Invalid order. Must be either [ASC|DESC]")
				}
			}
		} else {
			if len(order) == 1 && len(sortby) > 1 {
				for _, v := range sortby {
					if strings.ToUpper(order[0]) == "ASC" {
						orderBys = append(orderBys, v)
					} else if strings.ToUpper(order[0]) == "DESC" {
						orderBys = append(orderBys, fmt.Sprintf("-%v", v))
					} else {
						return nil, 0, errors.New("Error: Invalid order. Must be either [ASC|DESC]")
					}
				}
			} else {
				return nil, 0, errors.New("Error: 'sortby', 'order' sizes mismatch or 'order' size is not 1")
			}
		}
	} else {
		if len(order) > 0 {
			return nil, 0, errors.New("Error: unused 'order' fields")
		}
	}
	qs = qs.OrderBy(orderBys...)

	var authors []Author
	var list []interface{}
	num, err := qs.Limit(limit, offset).All(&authors, fields...)
	if err != nil {
		return nil, 0, err
	}
	if len(fields) > 0 {
		for _, v := range authors {
			var m = make(map[string]interface{})
			val := reflect.ValueOf(v)
			for _, field := range fields {
				m[field] = val.FieldByName(field).Interface()
			}
			list = append(list, m)
		}
	} else {
		for _, v := range authors {
			list = append(list, v)
		}
	}
	log.Debug("Function GetBooks return:{error:%v,num:%v,[]interface{}:%v}", err, num, list)
	return list, num, nil
}

func GetAuthorById(id int) (*Author, error) {
	log.Debug("Function GetAuthorById input param:{id:%v}", id)
	o := orm.NewOrm()
	author := &Author{Id: id}
	err := o.Read(author)
	log.Debug("Function GetAuthorById return:{error:%v,*Author:%v}", err, author)
	return author, err
}

func UpdateAuthorById(author *Author) error {
	log.Debug("Function UpdateAuthorById input param:{author:%v}", author)
	o := orm.NewOrm()
	var a Author
	a.Id = author.Id
	err := o.Read(&a)
	if err != nil {
		return err
	}
	author.CreatedTime = a.CreatedTime
	_, err = o.Update(author, "Name", "Email", "Profile")
	log.Debug("Function UpdateAuthorById return:{error:%v}", err)
	return err
}

func DeleteAuthorById(id int) error {
	log.Debug("Function DeleteAuthorById input param:{id:%v}", id)
	o := orm.NewOrm()
	author := &Author{Id: id}
	err := o.Read(author)
	if err != nil {
		log.Debug("Function DeleteAuthorById return:{error:%v}", err)
		return err
	}
	_, err = o.Delete(author)
	log.Debug("Function DeleteAuthorById return:{error:%v}", err)
	return err
}
